package com.minglead.springboot.platform.sys.utils;

import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.servlet.http.HttpServletRequest;

import org.apache.shiro.authz.annotation.RequiresPermissions;
import org.springframework.web.method.HandlerMethod;

import com.minglead.springboot.common.config.Global;
import com.minglead.springboot.common.utils.CacheUtils;
import com.minglead.springboot.common.utils.Exceptions;
import com.minglead.springboot.common.utils.SpringContextHolder;
import com.minglead.springboot.common.utils.StringUtils;
import com.minglead.springboot.platform.sys.dao.AreaDao;
import com.minglead.springboot.platform.sys.dao.LogDao;
import com.minglead.springboot.platform.sys.dao.MenuDao;
import com.minglead.springboot.platform.sys.entity.Area;
import com.minglead.springboot.platform.sys.entity.Log;
import com.minglead.springboot.platform.sys.entity.Menu;
import com.minglead.springboot.platform.sys.entity.User;


/**
 * 日志类
 */
public class LogUtils {
	
	public static final String CACHE_MENU_NAME_PATH_MAP = "menuNamePathMap";
	
	private static LogDao logDao = SpringContextHolder.getBean(LogDao.class);
	private static MenuDao menuDao = SpringContextHolder.getBean(MenuDao.class);
	
	/**
	 * 保存日志
	 */
	public static void saveLog(HttpServletRequest request,User user,String title){
		saveLog(request, user,null, null, title);
	}
	
	/**
	 * 保存日志
	 */
	public static void saveLog(HttpServletRequest request, User user,Object handler, Exception ex, String title){
	
		String uri=request.getRequestURI();
		if(!StringUtils.isEmpty(request.getQueryString()))
		uri = uri+"?"+request.getQueryString();
		Log log = new Log();
		log.setTitle(title);
		log.setType(ex == null ? Log.TYPE_ACCESS : Log.TYPE_EXCEPTION);
		log.setRemoteAddr(StringUtils.getRemoteAddr(request));
		log.setUserAgent(request.getHeader("user-agent"));
		log.setRequestUri(uri);
		log.setParams(request.getParameterMap());
		log.setMethod(request.getMethod());
		
	    String createUserName = user==null?"":user.getName();
	    String createUserOfficeName = (user==null||user.getOffice()==null)?"":user.getOffice().getName();
	    log.setCreateUserName(createUserName);
	    log.setCreateUserOfficeName(createUserOfficeName);		    
			// 异步保存日志
		new SaveLogThread(log, handler, ex).start();
	}

	/**
	 * 保存日志（登录失败）
	 */
	public static void saveLogLoginFail(HttpServletRequest request,String createUserName,String title){
			String uri=request.getRequestURI();
			Log log = new Log();
			log.setTitle(title);
			log.setType(Log.TYPE_ACCESS);
			log.setRemoteAddr(StringUtils.getRemoteAddr(request));
			log.setUserAgent(request.getHeader("user-agent"));
			log.setRequestUri(uri);
			log.setParams(request.getParameterMap());
			log.setMethod(request.getMethod());
			log.setCreateUserName(createUserName);
			log.preInsert();
			logDao.insert(log);
	}
	
	/**
	 * 保存日志线程
	 */
	public static class SaveLogThread extends Thread{
		
		private Log log;
		private Object handler;
		private Exception ex;
		
		public SaveLogThread(Log log, Object handler, Exception ex){
			super(SaveLogThread.class.getSimpleName());
			this.log = log;
			this.handler = handler;
			this.ex = ex;
		}
		
		@Override
		public void run() {
			// 获取日志标题
			if (StringUtils.isBlank(log.getTitle())){
				String permission = "";
				if (handler instanceof HandlerMethod){
					Method m = ((HandlerMethod)handler).getMethod();
					RequiresPermissions rp = m.getAnnotation(RequiresPermissions.class);
					permission = (rp != null ? StringUtils.join(rp.value(), ",") : "");
				}
				log.setTitle(getMenuNamePath(log.getRequestUri(), permission));
			}
			// 如果有异常，设置异常信息
			log.setException(Exceptions.getStackTraceAsString(ex));
			// 如果无标题并无异常日志，则不保存信息
			if (StringUtils.isBlank(log.getTitle()) && StringUtils.isBlank(log.getException())){
				return;
			}
			// 保存日志信息
			log.preInsert();
			logDao.insert(log);
		}
	}

	/**
	 * 获取菜单名称路径（如：系统设置-机构用户-用户管理-编辑）
	 */
	public static String getMenuNamePath(String requestUri, String permission){
		String href = StringUtils.substringAfter(requestUri, Global.getAdminPath());
		@SuppressWarnings("unchecked")
		Map<String, String> menuMap = (Map<String, String>)CacheUtils.get(CACHE_MENU_NAME_PATH_MAP);
		if (menuMap == null){
			menuMap = new HashMap<String,String>();
			List<Menu> menuList = menuDao.findAllList(new Menu());
			for (Menu menu : menuList){
				// 获取菜单名称路径（如：系统设置-机构用户-用户管理-编辑）
				String namePath = LogUtils.getMenuFullPathName(menu);
				if (StringUtils.isNotBlank(menu.getHref())){
					menuMap.put(menu.getHref(), namePath);
				}else if (StringUtils.isNotBlank(menu.getPermission())){
					for (String p : StringUtils.split(menu.getPermission())){
						menuMap.put(p, namePath);
					}
				}
				
			}
			CacheUtils.put(CACHE_MENU_NAME_PATH_MAP, menuMap);
		}
		String menuNamePath = menuMap.get(href);
		if (menuNamePath == null){
			if(StringUtils.isNotBlank(permission)){
				for (String p : StringUtils.split(permission)){
					menuNamePath = menuMap.get(p);
					if (StringUtils.isNotBlank(menuNamePath)){
						break;
					}
				}
			}
			if (menuNamePath == null){
				return "";
			}
		}
		return menuNamePath;
	}

	/**
	 * 根据当前菜单，返回菜单全路径，例如：报名信息管理，返回 报名信息管理-招生录取-招生管理
	 * @param m
	 * @return
	 */
	public static String getMenuFullPathName(Menu m){
		if(m==null)
		return null;
		String ret = m.getName();
		//最多支持4级，偷工减料
		Menu menuParent = menuDao.get(m.getParentId());
		if(menuParent!=null){
			ret = menuParent.getName()+"-"+ret;
			Menu menuParent0 = menuDao.get(menuParent.getParentId());
			if(menuParent0!=null){
				ret = menuParent0.getName()+"-"+ret;
				Menu menuParent1 = menuDao.get(menuParent0.getParentId());
				if(menuParent1!=null){
					ret = menuParent1.getName()+"-"+ret;
					Menu menuParent2 = menuDao.get(menuParent1.getParentId());
					
					if(menuParent2!=null){
						ret = menuParent2.getName()+"-"+ret;
					}	
				}	
			}		
		}
		return ret;
	}
}
